#ifdef FDD
#include "utils/fdb_page_encrypt.h"
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/mman.h>
#include "datatype/timestamp.h"
#include "catalog/pg_control.h"
#include "utils/palloc.h"
#include "pg_config.h"
#include "utils/elog.h"
#include "common/md5.h"
#include "storage/bufpage.h"
#include "common/scram-common.h"

//pd_flags PD_VALID_FLAG_BITS
#define PD_PAGE_DATA_ENCODED ((uint16)0x8000)
//TDE加密时跳过page header中pd_lower（不含）之前字段不加密，即pd_lsn、pd_checksum、pd_flags 不加密
#define TDEUnencrptySizeOfPageHeader (offsetof(PageHeaderData, pd_lower))


int g_tde_encrypt = FDB_ENCRYPT_TYPE_NONE;

typedef struct _FdbTypePageEncrypt{
    struct fdb_cipher_state  seckey;
    unsigned char         buff[BLCKSZ];
}FdbTypePageEncrypt;


static FdbTypePageEncrypt *g_fdbPageEncrypt = NULL;

#ifdef FDDGM
static void fc_uint32ToCharArray(uint32 fc_value, unsigned char fc_result[4]) 
{
    fc_result[0] = (char)(fc_value & 0xFF);
    fc_result[1] = (char)((fc_value >> 8) & 0xFF);
    fc_result[2] = (char)((fc_value >> 16) & 0xFF);
    fc_result[3] = (char)((fc_value >> 24) & 0xFF);
}
#endif

/* 检查TDE 透明加密的密钥文件格式为.txt时，如果密钥文件属于数据库owner，要求权限为0600或更低。如果密钥文件属于root，要求权限为0640或更低 */
/* 检查TDE 透明加密的密钥文件格式为非.txt时，如果密钥文件属于数据库owner，要求权限为0700或更低（但是至少需要x权限）。如果密钥文件属于root，要求权限为0740或更低（但是至少需要x权限） */
/* isallow_XUSER 表名是否允许当前用户对该文件具有可执行权限*/
static	bool fc_check_tde_key_file_permissions(const char *fc_key_file, bool fc_isallow_XUSER)
{
	struct stat fc_buf;

	if (stat(fc_key_file, &fc_buf) != 0)
	{
		ereport(PANIC,
				(errcode_for_file_access(),
				 errmsg("could not access TDE private key file \"%s\": %m",
						fc_key_file)));
		return false;
	}

	/* Key file must be a regular file */
	if (!S_ISREG(fc_buf.st_mode))
	{
		ereport(PANIC,
				(errcode(ERRCODE_CONFIG_FILE_ERROR),
				 errmsg("TDE private key file \"%s\" is not a regular file",
						fc_key_file)));
		return false;
	}

	/*
	 * Refuse to load key files owned by users other than us or root, and
	 * require no public access to the key file.  If the file is owned by us,
	 * require mode 0600 or less.  If owned by root, require 0640 or less to
	 * allow read access through either our gid or a supplementary gid that
	 * allows us to read system-wide certificates.
	 *
	 * Note that roughly similar checks are performed in
	 * src/interfaces/libpq/fe-secure-openssl.c so any changes here may need
	 * to be made there as well.  The environment is different though; this
	 * code can assume that we're not running as root.
	 *
	 * Ideally we would do similar permissions checks on Windows, but it is
	 * not clear how that would work since Unix-style permissions may not be
	 * available.
	 */
#if !defined(WIN32) && !defined(__CYGWIN__)
	if (fc_buf.st_uid != geteuid() && fc_buf.st_uid != 0)
	{
		ereport(PANIC,
				(errcode(ERRCODE_CONFIG_FILE_ERROR),
				 errmsg("TDE private key file \"%s\" must be owned by the database user or root",
						fc_key_file)));
		return false;
	}
	if(fc_isallow_XUSER)
	{
		if ((fc_buf.st_uid == geteuid() && fc_buf.st_mode & (S_IRWXG | S_IRWXO)) ||
			(fc_buf.st_uid == 0 && fc_buf.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)))
		{
			ereport(PANIC,
					(errcode(ERRCODE_CONFIG_FILE_ERROR),
					 errmsg("TDE private key file \"%s\" has group or world access",
							fc_key_file),
					 errdetail("TDE File must have permissions u=rwx (0700) or less if owned by the database user, or permissions u=rwx,g=r (0740) or less if owned by root.")));
			return false;
		}
	}
	else
	{
		if ((fc_buf.st_uid == geteuid() && fc_buf.st_mode & (S_IXUSR | S_IRWXG | S_IRWXO)) ||
			(fc_buf.st_uid == 0 && fc_buf.st_mode & (S_IXUSR| S_IWGRP | S_IXGRP | S_IRWXO)))
		{
			ereport(PANIC,
					(errcode(ERRCODE_CONFIG_FILE_ERROR),
					 errmsg("TDE private key file \"%s\" has group or world access",
							fc_key_file),
					 errdetail("TDE File must have permissions u=rw (0600) or less if owned by the database user, or permissions u=rw,g=r (0640) or less if owned by root.")));
			return false;
		}
	}

	
#endif

	return true;
}

//生成TDE中对指定对象进行加密的密钥，由 sha256(time + pid + random + object_name) 组成
//其中 object_name 的长度不能够大于 TDE_BUF_LEN - TDE_RANDOM_LEN - 20
static void fdb_gen_tde_encrypt_key(uint8 	*fc_obj_key, const char * fc_object_name)
{
#define TDE_RANDOM_LEN 32
#define TDE_BUF_LEN 96 // sysidentifier 最大长度为20个字符，tde_random为32个字符，
	uint64		fc_sysidentifier;
	struct timeval fc_tv;
	char		fc_tde_random[TDE_RANDOM_LEN+1];
	char	fc_buf[TDE_BUF_LEN+1];
	const char *fc_errstr = NULL;
	int fc_object_name_len = 0;
#ifdef FDDGM
	pg_cryptohash_type fc_hash_type = PG_SM3;
#else
	pg_cryptohash_type fc_hash_type = PG_SHA256;
#endif

	gettimeofday(&fc_tv, NULL);
	fc_sysidentifier = ((uint64) fc_tv.tv_sec) << 32;
	fc_sysidentifier |= ((uint64) fc_tv.tv_usec) << 12;
	fc_sysidentifier |= getpid() & 0xFFF;

	if(NULL == fc_object_name )
	{
		ereport(PANIC,
				(errcode(ERRCODE_INTERNAL_ERROR),
				 errmsg("object_name is NULL, could not generate secret TDE Encrypt key")));
		return;
	}


	fc_object_name_len = strlen(fc_object_name);

	if (fc_object_name_len < 1)
	{
		ereport(PANIC,
				(errcode(ERRCODE_INTERNAL_ERROR),
				 errmsg("object_name is NULL, could not generate secret TDE Encrypt key")));
		return;
	}

	if(fc_object_name_len > TDE_BUF_LEN - TDE_RANDOM_LEN - FDB_SYS_IDENTIFIER_LEN)
	{
		ereport(PANIC,
				(errcode(ERRCODE_INTERNAL_ERROR),
				 errmsg("object_name is too long:%d, could not generate secret TDE Encrypt key",fc_object_name_len)));
	}

	if (!pg_strong_random(fc_tde_random, TDE_RANDOM_LEN))
	{
		ereport(PANIC,
				(errcode(ERRCODE_INTERNAL_ERROR),
				 errmsg("could not generate secret TDE Encrypt key token for %s",fc_object_name)));
	}
	fc_tde_random[TDE_RANDOM_LEN] = '\0';

	snprintf(fc_buf, sizeof(fc_buf), "%llu%s%s", (unsigned long long)fc_sysidentifier,fc_tde_random,fc_object_name);
	fc_buf[TDE_BUF_LEN]  = '\0';

	if(fdb_cryptohash_binary( (unsigned char*)fc_buf, sizeof(fc_buf), fc_hash_type, fc_obj_key, &fc_errstr) < 0)
	{
		ereport(PANIC,
				(errcode(ERRCODE_INTERNAL_ERROR),
				 errmsg("could not calculate tde encrypt key hash: %s for %s", fc_errstr,fc_object_name)));
	}

}

static void fdb_initDSKEncrypt(const unsigned char *fc_Extkey, uint64 fc_mixkey,FDB_ENCRYPT_TYPE fc_gen_type)
{
	int fc_i = 0;	
	int fc_mixkey_len = 0;
	uint8	fc_DSK[FDB_DSKKEY_LEN] = {0};
	char fc_mixkey_str[FDB_DSKKEY_LEN+1] = {0};
	
	snprintf(fc_mixkey_str,sizeof(fc_mixkey_str), "%llu", (unsigned long long)fc_mixkey);
	fc_mixkey_str[FDB_DSKKEY_LEN] = '\0';

   //如果mixkey转为字符串后的长度，小于SCRAM_KEY_LEN，则填充补足，以避免mixkey长度小于16字节，导致sm4-xts加密失败
    fc_mixkey_len = strlen(fc_mixkey_str);  
	if(fc_mixkey_len < FDB_DSKKEY_LEN)
	{   
		for(fc_i = fc_mixkey_len; fc_i < FDB_DSKKEY_LEN; fc_i++)
		{
			fc_mixkey_str[fc_i] = fc_mixkey_str[fc_i-fc_mixkey_len];
		}
	}

	if(PD_VALID_FLAG_BITS & PD_PAGE_DATA_ENCODED)
	{
		ereport(PANIC,
			(errcode(ERRCODE_WARNING),
				errmsg("Failed to initial transparent encryption. pd_flags without reserved bit")));
	}
	if(NULL == g_fdbPageEncrypt)
	{		
	    void *fc_ptr = NULL;
		int fc_ret = 0;
		//madvise需要对齐的空间，因为g_fdbPageEncrypt的长度是 BLCKSZ + sizeof(fdb_cipher_state) < BLCKSZ*2
		int fc_len = posix_memalign(&fc_ptr, BLCKSZ, BLCKSZ*2);
		g_fdbPageEncrypt = (FdbTypePageEncrypt*)fc_ptr;
		if(NULL == g_fdbPageEncrypt || fc_len != 0)
		{
			ereport(PANIC,
				(errcode(ERRCODE_WARNING),
					errmsg("Failed to malloc FdbTypePageEncrypt,%d",fc_len)));
		}

		/*通过对madvise设置MADV_DONTDUMP，来防止core dump泄漏密钥*/
		fc_ret = madvise(g_fdbPageEncrypt, BLCKSZ*2, MADV_DONTDUMP);
		if (fc_ret != 0)
		{
	        ereport(ERROR,	(errmsg("madvise pkey fail to g_fdbPageEncrypt")));
	    }
		/*通过mlock 来防止密钥被放到交换区*/
		fc_ret = mlock(g_fdbPageEncrypt, BLCKSZ*2);
		if (fc_ret != 0) 
		{
	       ereport(ERROR,	(errmsg("mlock perm pkey to g_fdbPageEncrypt: %d",fc_ret)));
	    }
	}
	

	//1、先用外部密钥Extkey对系统标识mixkey进行加密，用于生成数据库系统密钥DSK
	//在国密场景下，用外部密钥Extkey做为sm4-xts的key，并且取Extkey的中间来个字节做为tweak值
	fdb_cipher_init(&g_fdbPageEncrypt->seckey, fc_gen_type, fc_Extkey, FDB_DSKKEY_LEN, fc_Extkey+8);

	//用sm4-xts或rc4算法进行对 mixkey 进行加密后， 得到用于加密对象密钥obj_key的密钥 DSK
	fdb_encrypt(&g_fdbPageEncrypt->seckey, ( unsigned char *)fc_mixkey_str, fc_DSK, FDB_DSKKEY_LEN);

	//2、再用DSK，对对象密钥obj_key进行加密 或对tde_encrypt_tablekey进行解密
	//在国密场景下，用前面生成的kek做为sm4-xts的key，并且取kek的中间来个字节做为tweak值
	fdb_cipher_init(&g_fdbPageEncrypt->seckey, fc_gen_type, fc_DSK, FDB_DSKKEY_LEN, fc_DSK+8);

	return;
}

//初始化 TDE 加密密钥
//注意当is_new_gen_key为true时，会给 tde_encrypt_tablekey 赋值最新计算的对象密钥被加密后的密钥
int fdb_initPageEncrypt(const unsigned char *fc_Extkey, uint64 fc_mixkey,unsigned char * fc_tde_encrypt_tablekey, FDB_ENCRYPT_TYPE fc_type, bool fc_is_new_gen_key)
{  
	uint8	fc_obj_key[FDB_OBJKEY_LEN] = {0};

#ifdef FDDGM
	FDB_ENCRYPT_TYPE fc_gen_type = FDB_ENCRYPT_TYPE_SM4;
#else
    FDB_ENCRYPT_TYPE fc_gen_type = FDB_ENCRYPT_TYPE_RC4;
#endif

    fdb_initDSKEncrypt(fc_Extkey, fc_mixkey, fc_gen_type);
	if(fc_is_new_gen_key)
	{
	    #define TDE_TABLE_ENCRYPT_OBJ_NAME "TABLE"	
		//生成对象密钥obj_key
		fdb_gen_tde_encrypt_key(fc_obj_key,TDE_TABLE_ENCRYPT_OBJ_NAME);
		
		//将生成的对象密钥 obj_key，用sm4-xts或rc4算法进行加密后保存到tde_encrypt_tablekey中
		fdb_encrypt(&g_fdbPageEncrypt->seckey, fc_obj_key, fc_tde_encrypt_tablekey, FDB_OBJKEY_LEN);		
	}
	else
	{
	    //将用sm4-xts或rc4算法进行对 tde_encrypt_tablekey 进行解密后， 得到对象密钥 obj_key
		fdb_decrypt(&g_fdbPageEncrypt->seckey, fc_tde_encrypt_tablekey, fc_obj_key, TDE_ENCRYPT_TABLE_KEY_LEN);
	}   
    //3、最后用对象密钥obj_key，做为TDE中对表数据进行加密的加密秘钥
	fdb_cipher_init(&g_fdbPageEncrypt->seckey,fc_type, fc_obj_key, FDB_OBJKEY_LEN, NULL);
	memset(fc_obj_key, 0, FDB_OBJKEY_LEN);	
    return 0;
}

//更新对象密钥被加密的密钥，步骤为：
//1、先用旧的old_Extkey计算出DSK， 然后该DSK从tde_encrypt_tablekey中解除对象密钥obj_key
//2、接着用最新的Extkey重新计算出DSK，然后用该DSK对对象密钥进行加密并且更新到 tde_encrypt_tablekey 中
int fdb_updatePageEncrypt(const unsigned char *fc_old_Extkey, const unsigned char *fc_new_Extkey, uint64 fc_mixkey,unsigned char * fc_tde_encrypt_tablekey, FDB_ENCRYPT_TYPE fc_type)
{   
	
	uint8	fc_obj_key[FDB_OBJKEY_LEN+1] = {0};
#ifdef FDDGM
	FDB_ENCRYPT_TYPE fc_gen_type = FDB_ENCRYPT_TYPE_SM4;
#else
    FDB_ENCRYPT_TYPE fc_gen_type = FDB_ENCRYPT_TYPE_RC4;
#endif
    fdb_initDSKEncrypt(fc_old_Extkey, fc_mixkey, fc_gen_type);

	//先用旧的old_Extkey对 tde_encrypt_tablekey 进行解密后， 得到对象密钥 obj_key
	fdb_decrypt(&g_fdbPageEncrypt->seckey, fc_tde_encrypt_tablekey, fc_obj_key, TDE_ENCRYPT_TABLE_KEY_LEN);

	//接着用新的 new_Extkey 做为加密密钥
	fdb_initDSKEncrypt(fc_new_Extkey, fc_mixkey, fc_gen_type);

	//将解密得到的对象密钥 obj_key，用sm4-xts或rc4算法用新的new_Extkey ，对其   进行加密后跟新到tde_encrypt_tablekey中
	fdb_encrypt(&g_fdbPageEncrypt->seckey, fc_obj_key, fc_tde_encrypt_tablekey, FDB_OBJKEY_LEN);	
	
    //最后用对象密钥obj_key，做为TDE中对表数据进行加密的加密秘钥
	fdb_cipher_init(&g_fdbPageEncrypt->seckey,fc_type, fc_obj_key, FDB_OBJKEY_LEN, NULL);
	memset(fc_obj_key, 0, FDB_OBJKEY_LEN);	
    return 0;
}


void fdb_destroyPageEncrypt(void)
{
    if(NULL != g_fdbPageEncrypt)
    {
        free(g_fdbPageEncrypt);
        g_fdbPageEncrypt = NULL;
    }
}

#define FDB_MAX_CMD_LEN 4096
void fdb_getPageEncryptKey(char *fc_program, unsigned char *fc_Extkey)
{
	const char *fc_errstr = NULL;
    FILE    *fc_fp = NULL;
    char    *fc_buf = NULL;
    int     fc_len = 0;
#ifdef FDDGM
	pg_cryptohash_type fc_hash_type = PG_SM3;
#else
	pg_cryptohash_type fc_hash_type = PG_SHA256;
#endif

    fc_buf = (char *)malloc(FDB_MAX_CMD_LEN);
    if(NULL == fc_buf)
    {
        ereport(PANIC,
            (errcode(ERRCODE_WARNING),
                errmsg("Failed to get KEY for transparent encryption. memory allocate failed")));
    }
    fc_len = strlen(fc_program);
    if( fc_len > 4 && 't' == (fc_program[fc_len-1] | 0x20) && 'x' == (fc_program[fc_len-2] | 0x20) && 't' == (fc_program[fc_len-3] | 0x20) && '.' == fc_program[fc_len-4])
    {
    	//如果是txt格式的文件，只需要有读写权限即可
    	if (!fc_check_tde_key_file_permissions(fc_program,false))
		{
			//如果异常会直接打印 PANIC 认证退出
			free(fc_buf);
		    return;
		}	
		
        fc_fp = fopen(fc_program, "r");
        if(fc_fp == NULL)
        {
            free(fc_buf);
            ereport(PANIC,
                (errcode(ERRCODE_WARNING),
                    errmsg("Failed to open file to get KEY for transparent encryption. file is: [%s]", fc_program)));
			return;
        }
        fc_len = fread(fc_buf, 1, FDB_MAX_CMD_LEN, fc_fp);
        fclose(fc_fp);
        if(fc_len <= 0)
        {
            free(fc_buf);
            ereport(PANIC,
                (errcode(ERRCODE_WARNING),
                    errmsg("Failed to read file to get KEY for transparent encryption. file is: [%s]", fc_program)));
        }
    }
    else
    {
	    //如果是其他格式的文件，则需要有额外的可执行权限
    	if (!fc_check_tde_key_file_permissions(fc_program,true))
		{
			//如果异常会直接打印 PANIC 认证退出
			free(fc_buf);
		    return;
		}
	
        fc_fp = popen(fc_program, "r");
        fc_buf[0] = 0;
        if(NULL == fc_fp || fgets(fc_buf, FDB_MAX_CMD_LEN, fc_fp) == NULL)
        {
            free(fc_buf);
            if(NULL != fc_fp)
            {
                pclose(fc_fp);
            }
            ereport(PANIC,
                (errcode(ERRCODE_WARNING),
                    errmsg("Failed to execute command to get KEY for transparent encryption. command is: [%s]",
                        fc_program)));
			return;
        }
        pclose(fc_fp);
        fc_len = strlen(fc_buf);
        if (0 == fc_len || strncmp(fc_buf, "ERROR:", 6) == 0)
        {
            ereport(PANIC,
                (errcode(ERRCODE_WARNING),
                    errmsg("Failed to get KEY for transparent encryption. %s", fc_len == 0 ? "<NULL>" : fc_buf)));
			free(fc_buf);
			return;
        }
    }
    //去掉最后的回车换行
    for(; fc_buf[fc_len-1] == 0x0D || fc_buf[fc_len-1] == 0x0A; )
    {
        fc_len--;
    }
    fc_buf[fc_len] = 0;

	if(fc_len < FDB_TDE_PASSWD_MINLEN)
	{
		free(fc_buf);
        ereport(PANIC,
            (errcode(ERRCODE_WARNING),
                errmsg("The TDE KEY for transparent encryption must be at least 6 characters.")));
		return;
	}

	if(fdb_cryptohash_binary((unsigned char*)fc_buf, fc_len, fc_hash_type, fc_Extkey, &fc_errstr) < 0)
    {
        free(fc_buf);
        ereport(PANIC,
            (errcode(ERRCODE_WARNING),
                errmsg("Failed to get KEY for transparent encryption. hash failed(%s) .",fc_errstr)));
		return;
    }
    free(fc_buf);
}

uint64 fdb_getPageEncryptChkKey(const unsigned char *fc_Extkey, uint64 fc_mixkey, const unsigned char * fc_tde_encrypt_tablekey)
{
    uint8	fc_hmac_key[SCRAM_KEY_LEN] = {0};//外部密钥fkey 和 mixkey进行hamc计算后得到的摘要值
	const char    *fc_errstr = NULL;
	char    fc_mixkey_str[FDB_SYS_IDENTIFIER_LEN + 1] = {0}; 
	uint8	fc_hmac_dek[SCRAM_KEY_LEN] = {0};//将 hmac_key 和 tde_encrypt_tablekey 进行hamc计算后得到的摘要值
	uint64  *fc_pSeed = NULL;
#ifdef FDDGM
	pg_cryptohash_type fc_hash_type = PG_SM3;
#else
	pg_cryptohash_type fc_hash_type = PG_SHA256;
#endif

	snprintf(fc_mixkey_str, (FDB_SYS_IDENTIFIER_LEN + 1), "%llu", (unsigned long long)fc_mixkey);

	if(fdb_hmac(fc_Extkey,FDB_EXTKEY_LEN,  (unsigned char*)fc_mixkey_str, FDB_SYS_IDENTIFIER_LEN, SCRAM_DEFAULT_ITERATIONS, fc_hash_type, fc_hmac_key, &fc_errstr) < 0)
	{
		ereport(PANIC,
				(errcode(ERRCODE_INTERNAL_ERROR),
				 errmsg("Generate an HMAC key using the fdb_hmac fails.(%s)",fc_errstr)));
	}

	if(fdb_hmac(fc_hmac_key,SCRAM_KEY_LEN, fc_tde_encrypt_tablekey, TDE_ENCRYPT_TABLE_KEY_LEN, SCRAM_DEFAULT_ITERATIONS, fc_hash_type, fc_hmac_dek, &fc_errstr) < 0)
	{
		ereport(PANIC,
				(errcode(ERRCODE_INTERNAL_ERROR),
				 errmsg("Generate an HMAC data encrypt key using the fdb_hmac fails.(%s)",fc_errstr)));
	}
	
	fc_pSeed = (uint64*)fc_hmac_dek;
	fc_mixkey = fc_pSeed[0] ^ fc_pSeed[1] ^ fc_pSeed[2] ^ fc_pSeed[3];   
    return fc_mixkey;
}

uint64 fdb_checkPageEncryptSecKey(const unsigned char *fc_fkey, uint64 fc_mixkey, const unsigned char * fc_tde_encrypt_tablekey, uint64 fc_chkkey)
{
	uint64 fc_crc_64 = fdb_getPageEncryptChkKey(fc_fkey, fc_mixkey, fc_tde_encrypt_tablekey);
	fc_chkkey = fc_chkkey ^ fc_crc_64;
	return fc_chkkey;
}


void * fdb_encodePage(void *fc_pageData, uint32 fc_blocknum)
{
    PageHeaderData  *fc_pHead = (PageHeaderData*)fc_pageData;

    if(NULL != g_fdbPageEncrypt && !PageIsEmpty(fc_pHead))
    {
#ifdef FDDGM
		if(FDB_ENCRYPT_TYPE_SM4 == g_fdbPageEncrypt->seckey.type)
		{
			//给iv低四字节赋值为blocknum，中间八字节赋值为LSN，以便每个blocknum，即使数据一样，密钥一样，加密后的结果也不一样
       		fc_uint32ToCharArray(fc_blocknum,g_fdbPageEncrypt->seckey.iv);
			//给iv中间八字节赋值为LSN，
			fc_uint32ToCharArray(fc_pHead->pd_lsn.xrecoff, g_fdbPageEncrypt->seckey.iv+4);
			fc_uint32ToCharArray(fc_pHead->pd_lsn.xlogid, g_fdbPageEncrypt->seckey.iv+8);
		}
#endif

		if(FDB_ENCRYPT_TYPE_RC4 == g_fdbPageEncrypt->seckey.type)
		{
			fdb_cipher_reset(&g_fdbPageEncrypt->seckey);
		}
        fdb_encrypt(&g_fdbPageEncrypt->seckey, ((unsigned char*)fc_pageData) + TDEUnencrptySizeOfPageHeader, g_fdbPageEncrypt->buff + TDEUnencrptySizeOfPageHeader, BLCKSZ - TDEUnencrptySizeOfPageHeader);

        fc_pHead = (PageHeaderData*)g_fdbPageEncrypt->buff;
        memcpy(fc_pHead, fc_pageData, TDEUnencrptySizeOfPageHeader);
        fc_pHead->pd_flags |= PD_PAGE_DATA_ENCODED;
        fc_pageData = g_fdbPageEncrypt->buff;
    }
    return fc_pageData;
}

void fdb_decodePage(void *fc_pageData, uint32 fc_blocknum)
{
    PageHeaderData  *fc_pHead = (PageHeaderData*)fc_pageData;

    if(NULL != g_fdbPageEncrypt && (fc_pHead->pd_flags & PD_PAGE_DATA_ENCODED))
    {
#ifdef FDDGM
		if(FDB_ENCRYPT_TYPE_SM4 == g_fdbPageEncrypt->seckey.type)
		{
			//给iv低四节赋值为blocknum，中间八字节赋值为LSN，以便每个blocknum，即使数据一样，密钥一样，加密后的结果也不一样
			fc_uint32ToCharArray(fc_blocknum, g_fdbPageEncrypt->seckey.iv);
			//给iv中间八字节赋值为LSN，
			fc_uint32ToCharArray(fc_pHead->pd_lsn.xrecoff, g_fdbPageEncrypt->seckey.iv+4);
			fc_uint32ToCharArray(fc_pHead->pd_lsn.xlogid, g_fdbPageEncrypt->seckey.iv+8);
			
		}
#endif

        if(FDB_ENCRYPT_TYPE_RC4 == g_fdbPageEncrypt->seckey.type)
		{
			fdb_cipher_reset(&g_fdbPageEncrypt->seckey);
		}
        fdb_decrypt(&g_fdbPageEncrypt->seckey, ((unsigned char*)fc_pageData) + TDEUnencrptySizeOfPageHeader, ((unsigned char*)fc_pageData) + TDEUnencrptySizeOfPageHeader, BLCKSZ- TDEUnencrptySizeOfPageHeader);

        fc_pHead->pd_flags &= ~PD_PAGE_DATA_ENCODED;
    }
}

#endif //FDD
